﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using NopSolutions.NopCommerce.BusinessLogic;
using brevis.Nop.BusinessLogic.Data;
using System.IO;
using brevis.Nop.SDK.Entity;
using brevis.Nop.SDK;
using brevis.Nop.SDK.ReportDataGetter;
using Microsoft.Reporting.WebForms;

namespace brevis.Nop.BusinessLogic.Reports
{
    /// <summary>
    /// Report service
    /// </summary>
    public class ReportService
    {
        #region Fields

        /// <summary>
        /// Nop context
        /// </summary>
        private readonly NopContext _nopContext;

        /// <summary>
        /// Http context
        /// </summary>
        private readonly HttpContext _httpContext;

        #endregion

        #region Ctor

        /// <summary>
        /// Creates a report service instance
        /// </summary>
        /// <param name="nopcontext">Nop context</param>
        /// <param name="httpcontext">Http context</param>
        public ReportService(NopContext nopcontext, HttpContext httpcontext)
        {
            _nopContext = nopcontext;
            _httpContext = httpcontext;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Returns a report configuration
        /// </summary>
        /// <param name="reportid">Report ID</param>
        /// <returns>NopReport</returns>
        public NopReport GetNopReport(string reportid)
        {
            return brevisNopDataManager.NopReport_Get(reportid);
        }

        /// <summary>
        /// Returns a local report with added datasource and parameters
        /// </summary>
        /// <param name="reportid">Report ID</param>
        /// <returns>LocalReport</returns>
        public LocalReport GetLocalReport(string reportid)
        {
            var nopReport = GetNopReport(reportid);
            var localReport = new LocalReport();
            localReport.ReportPath = nopReport.Configuration.ReportPath;

            // run checks
            this.DoChecks(nopReport.Configuration.Check);

            // attach parameters
            this.AttachParameterVaulues(localReport, nopReport);

            // attach datasources
            this.AttachDataSets(localReport, nopReport);

            return localReport; // ret;
        }

        /// <summary>
        /// Returns a byte array of an localreport for binary write in http response
        /// </summary>
        /// <param name="reportid">Report ID</param>
        /// <returns>byte array</returns>
        public byte[] GetLocalReportBytes(string reportid)
        {
            // declare out var's
            Warning[] warnings;
            string[] streamids;
            string mimeType;
            string encoding;
            string extension;

            // get localreport by report id
            var report = GetLocalReport(reportid);

            // render in byte array
            byte[] bytes = report.Render(
                "PDF", null, out mimeType, out encoding, out extension, out streamids, out warnings);

            return bytes;

        }

        #endregion

        #region Utilities

        /// <summary>
        /// Attaches data to report
        /// </summary>
        /// <param name="localreport">LocalReport</param>
        /// <param name="nopreport">NopReport config.</param>
        private void AttachDataSets(LocalReport localreport, NopReport nopreport)
        {
            if (nopreport.Configuration.DataSet == null
                || nopreport.Configuration.DataSet.Count == 0)
                return;

            var dataGetterFactory = new InterfaceFactory<IReportDataGetter>();

            foreach (var ds in nopreport.Configuration.DataSet)
            {
                localreport.DataSources.Add(new Microsoft.Reporting.WebForms.ReportDataSource
                {
                    Name = ds.Key,
                    Value = ds.DataGetterInstance.Get()
                });
            }
        }

        /// <summary>
        /// Attaches values to parameter
        /// </summary>
        /// <param name="localreport">LocalReport</param>
        /// <param name="nopreport">NopReport config.</param>
        private void AttachParameterVaulues(LocalReport localreport, NopReport nopreport)
        {
            if (nopreport.Configuration.Parameter == null
                || nopreport.Configuration.Parameter.Count == 0)
                return;

            var execParams = new List<ReportParameter>(); 
            foreach (var p in nopreport.Configuration.Parameter)
            {
                var getMethArgs = p.GetMethodAttribute.ToArray();
                var gettedValue = p.DataGetterInstance.Get(getMethArgs);
                execParams.Add(new ReportParameter(p.Key, gettedValue.ToString()));
            }

            localreport.SetParameters(execParams);
        }

        /// <summary>
        /// Runs all checks an returns true if all ok
        /// </summary>
        /// <param name="checks">List of all check in nopreport configuration</param>
        /// <returns>
        /// If a check is failed, the check throws an exception
        /// </returns>
        private void DoChecks(List<NopReportCheck> checks)
        {
            foreach (var c in checks)
            {
                c.CheckerInstance.Execute(
                    new object[2] { _nopContext, _httpContext });
            }
        }

        #endregion
    }
}
